import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt

"""
实现Hariis检测使用的API是：
    dst=cv.cornerHarris(src, blockSize, ksize, k)
参数：
    img：数据类型为 ﬂoat32 的输入图像。
    blockSize：角点检测中要考虑的邻域大小。
    ksize：sobel求导使用的核大小
    k ：角点检测方程中的自由参数，取值参数为 [0.04，0.06].
"""

# Harris角点检测算法(像素级)
img = cv.imread("image/tv.jpg")
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) # 转换为灰度图
gray = np.float32(gray) # 输入图像必须是float32

dst = cv.cornerHarris(gray, 2, 3, 0.04)
img[dst > 0.001 * dst.max()] = [0, 0, 255]
plt.imshow(img[:, :, ::-1])
plt.show()

"""
实现Shi-Tomasi角点检测使用API:
    corners = cv2.goodFeaturesToTrack ( image, maxcorners, qualityLevel, minDistance )
参数：
    Image: 输入灰度图像
    maxCorners : 获取角点数的数目。
    qualityLevel：该参数指出最低可接受的角点质量水平，在0-1之间。
    minDistance：角点之间最小的欧式距离，避免得到相邻特征点。
返回：
    Corners: 搜索到的角点，在这里所有低于质量水平的角点被排除掉，然后把合格的角点按质量排序，
    然后将质量较好的角点附近（小于最小欧式距离）的角点删掉，最后找到maxCorners个角点返回。
"""

# Shi-Tomasi角点检测算法(Harris的改进,都具有旋转不变性，但是不具备尺度不变性)
img = cv.imread("image/tv.jpg")
gray1 = cv.cvtColor(img, cv.COLOR_BGR2GRAY) # 转换为灰度图
corners = cv.goodFeaturesToTrack(gray1, 1000, 0.01, 10)
for corner in corners:
    x, y = corner.ravel()
    cv.circle(img, (x, y), 2, (0, 0, 255), -1)
plt.imshow(img[:, :, ::-1])
plt.show()



# SIFT角点检测算法(opencv-python	3.4.2.17	opencv-contrib-python	3.4.2.16, 这是一个可用的版本组合)
img1 = cv.imread("image/tv.jpg")
gray2 = cv.cvtColor(img, cv.COLOR_BGR2GRAY) # 转换为灰度图
# 实例化sift
sift = cv.xfeatures2d.SIFT_create()
"""
    kp,des = sift.detectAndCompute(gray,None)
参数：
    gray: 进行关键点检测的图像，注意是灰度图像
返回：
    kp: 关键点信息，包括位置，尺度，方向信息
    des: 关键点描述符，每个关键点对应128个梯度信息的特征向量
"""
# 检测关键点并计算
kp, des = sift.detectAndCompute(gray2, None)
"""
    cv.drawKeypoints(image, keypoints, outputimage, color, flags)
参数：
    image: 原始图像
    keypoints：关键点信息，将其绘制在图像上
    outputimage：输出图片，可以是原始图像
    color：颜色设置，通过修改（b,g,r）的值,更改画笔的颜色，b=蓝色，g=绿色，r=红色。
    flags：绘图功能的标识设置
    cv2.DRAW_MATCHES_FLAGS_DEFAULT：创建输出图像矩阵，使用现存的输出图像绘制匹配对和特征点，对每一个关键点只绘制中间点
    cv2.DRAW_MATCHES_FLAGS_DRAW_OVER_OUTIMG：不创建输出图像矩阵，而是在输出图像上绘制匹配对
    cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS：对每一个特征点绘制带大小和方向的关键点图形
    cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS：单点的特征点不被绘制
SURF算法的应用与上述流程是一致，这里就不在赘述。
"""
# 将关键点检测结果绘制在图像上
cv.drawKeypoints(img1, kp, img, flags=cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
plt.imshow(img[:, :, ::-1])
plt.show()


# Fast角点检测算法(实时比较时检测较快，但是噪声较高的时候不过稳定，这时需要调整合适的阈值)
# (Opencv中的fast算法没有采用机器学习的模型，所以检测效果没那么好)
img2 = cv.imread("image/tv.jpg")
# 实例化fast
fast = cv.FastFeatureDetector_create(threshold=30)
kp = fast.detect(img2, None)
img3 = cv.drawKeypoints(img2, kp, None, color=(255, 255, 0))
plt.imshow(img3[:, :, ::-1])
plt.show()
# 去除极大值抑制
fast.setNonmaxSuppression(0)
kp = fast.detect(img2, None)
img4 = cv.drawKeypoints(img2, kp, None, color=(0, 255, 255))
plt.imshow(img4[:, :, ::-1])

# ORB算法
img = cv.imread("image/tv.jpg")
# 实例化orb
orb = cv.ORB_create(nfeatures=5000)
kp, des = orb.detectAndCompute(img, None)
img2 = cv.drawKeypoints(img, kp, None, flags=0)
plt.imshow(img2[:, :, ::-1])
plt.show()
